package com.shun.gateway.filter;

import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.shun.gateway.exception.ApiGatewayException;
import com.shun.gateway.msg.GatewayErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 为API提供的RSA通讯加密,私钥解密
 * @author clever
 * @since 2021-09-08
 */
@Slf4j
@Component
public class ApiRSADispatchGatewayFilterFactory extends AbstractGatewayFilterFactory {

    //设备键名
    private final static String DEV_KEY = "dev";

    private final List<HttpMessageReader<?>> messageReaders;

    public ApiRSADispatchGatewayFilterFactory() {
        this.messageReaders = HandlerStrategies.withDefaults().messageReaders();
    }

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            log.debug("RSA过滤器...");
            ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);
            log.debug("http方法：{}，报文类型：{}", serverRequest.method().name(), serverRequest.headers());
            //客户上传的代理
            String userAgentStr = serverRequest.headers().firstHeader("User-Agent");
            //user-agent代理
            UserAgent agent = UserAgentUtil.parse(userAgentStr);
            //设备类型 1 PC,2 Android,3 IOS,4 Pad,5 全部通用
            String dev = agent.getOs()!=null?agent.getOs().toString():serverRequest.headers().firstHeader(DEV_KEY);
            //判断content-type类型是否为application/json
            if(serverRequest.headers().contentType().get().includes(MediaType.APPLICATION_JSON)){
                //渠道号
                Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
                    log.info("通讯报文内容：{}", body);
                    return Mono.just(body);
                }).switchIfEmpty(Mono.defer(() -> {
                    log.info("通讯报文内容：empty");
                    return Mono.just(null);
                }));
                BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
                HttpHeaders headers = new HttpHeaders();
                headers.putAll(exchange.getRequest().getHeaders());
                headers.set("Content-Type", "application/json");
                CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
                return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
                    ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
                    return chain.filter(exchange.mutate().request(decorator).build());
                })).onErrorResume((throwable) -> {
                    return Mono.error(new Exception("异常！"));
                });
            }
            return Mono.error(new ApiGatewayException(GatewayErrorCode.NO_CONTENT_TYPE));
        };
    }

    ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) {
        return new ServerHttpRequestDecorator(exchange.getRequest()) {
            public HttpHeaders getHeaders() {
                long contentLength = headers.getContentLength();
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(headers);
                if (contentLength > 0L) {
                    httpHeaders.setContentLength(contentLength);
                } else {
                    httpHeaders.set("Transfer-Encoding", "chunked");
                }
                return httpHeaders;
            }
            public Flux<DataBuffer> getBody() {
                return outputMessage.getBody();
            }
        };
    }
}
